package link.ahsj.sqlserver.utils;

//import cn.hutool.core.io.file.FileReader;
import cn.hutool.core.io.watch.SimpleWatcher;
import cn.hutool.core.io.watch.WatchMonitor;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import link.ahsj.sqlserver.entity.Demo;
import link.ahsj.sqlserver.entity.ReqVo;
import link.ahsj.sqlserver.entity.ResVo;
import link.ahsj.sqlserver.entity.ScxsResVo;
import link.ahsj.sqlserver.exception.BaseBusinessException;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.nio.file.Path;
import java.nio.file.WatchEvent;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;

@Slf4j
public class FileUtil {
    /**
     * 应答文件地址
     */
    public static final String REPLY_PATH = "D:/易联众药企通/yddjjk/reply.txt";
    /**
     * 测试应答文件是否被占用的临时文件地址
     */
    public static final String REPLY_PATH_TEST = "D:/易联众药企通/yddjjk/reply1.txt";
    /**
     * 请求输入文件地址
     */
    public static final String REQUEST_PATH = "D:/易联众药企通/yddjjk/request.txt";
    /**
     * 测试请求输入文件是否被占用的临时文件地址
     */
    public static final String REQUEST_PATH_TEST = "D:/易联众药企通/yddjjk/request1.txt";
    /**
     * 超时时间
     */
    public static final long TIME_OUT_MINITE= 5L;

    /**
     * 检测当前文件是否被占用,如果被占用则等待
     * 同时删除应答文件和上一次的响应文件
     */
    public static void checkFile() {
        File f = new File(REQUEST_PATH);
        File f1 = new File(REQUEST_PATH_TEST);
        if (f.exists()) {
            //使用renameto来判断文件是否完成,如果未完成,则不可以拷贝,否则创建过程中我们操作会报错
            while (true) {
                f.renameTo(f1);//文件重命名
                if (f.exists()) {
                    log.info("++++++request文件正在被占用+++++++");
                    continue;
                } else {
                    f1.renameTo(f);
                }
                break;
            }
            f.delete();//删除之前的应答文件
        }
        File delfile = new File(REPLY_PATH);
        if (delfile.exists()) {
            delfile.delete();
        }
    }

    /**
     * 对文件进行监听
     *
     * @param reply
     * @param flag
     */
    public static WatchMonitor monitorFileChange(File reply, boolean[] flag) {
        WatchMonitor watchMonitor = WatchMonitor.createAll(reply, new SimpleWatcher() {
            @Override
            public void onCreate(WatchEvent<?> event, Path currentPath) {
                log.info("++++++正在创建文件,但是不代表文件修改完成+++++++");
                flag[0] = false;
                log.info("++++++++++++++++++++++reply应答文件已创建,flag[0]=" + flag[0]);
            }
        });
        watchMonitor.start();
        return watchMonitor;
    }

    /**
     * 产生请求入参文件
     *
     * @param reply
     * @param flag
     * @param param
     * @throws IOException
     */
    public static void createReqFile(File reply, boolean[] flag, Object param, String method) throws IOException,BaseBusinessException {
        log.info("------------------进入CreateReqFile-----------------------");
        ReqVo reqVo = new ReqVo();
        reqVo.setMethod(method);
        reqVo.setRequest("TRUE");
        reqVo.setParam(param);
        //请求出参结果
        String result = "";
        //请求出参对象
        ResVo resVo = new ResVo();


        if (reply.exists()){
            reply.delete();
        }
        writeJsonToTxt(reqVo);
        //使程序阻塞,等待文件变动,当产生应答文件后,跳出死循环(此时存在一种情况就是应答文件正在创建,但是还没有创建完成,文件被占用因此才会有两个此死循环判断)
        if (flag[0]) {
            log.info("程序阻塞,等待创建响应文件");
        }
        //这里要在循环外面加一个日期,循环里面创建一个日期进行比较,如果超时,则退出程序并且抛出异常
        LocalDateTime start = LocalDateTime.now();
        while (flag[0]) {
            LocalDateTime end = LocalDateTime.now();
            long between = ChronoUnit.MINUTES.between(start, end);
            if (between >= TIME_OUT_MINITE) {
                log.error("请求超时,医保程序并未响应,生成记录文件,并将request文件删除,下次定时任务时候将此时间段信息查出");
                throw new BaseBusinessException(500, "请求超时,医保程序并未响应,生成记录文件,并将request文件删除,下次定时任务时候将此时间段信息查出");
            }
        }
        File f = new File(REPLY_PATH);
        File f1 = new File(REPLY_PATH_TEST);
        //使用renameto来判断文件是否完成(是否被其他程序占用),如果未完成,则不可以拷贝,否则创建过程中我们操作会报错
        log.info("++++++等待reply文件完全创建完成+++++++");
        while (true) {
            f.renameTo(f1);
            if (f.exists()) {
                //log.info("++++++reply文件正在被占用+++++++");
                //如果文件被占用,继续死循环
                //f1.delete();
                continue;
            } else {
                f1.renameTo(f);
            }
            log.info("++++++reply创建文件正式完成+++++++");
            //生成响应文件后重新读取相应内容
            //FileReader fileReader = new FileReader(REPLY_PATH);
            StringBuffer sbf = new StringBuffer();
            try(BufferedReader reader=new BufferedReader(new FileReader(f));){
                String tempStr;
                while ((tempStr = reader.readLine()) != null) {
                    sbf.append(tempStr);
                }
                reader.close();
                result = sbf.toString();
                resVo = JSONUtil.parseObj(result).toBean(ResVo.class);
            }catch (Exception e){
                log.error(e.toString());
            }


            break;
        }
        log.info("程序阻塞退出,已经创建响应文件");
        //假设对方程序应答文件产生
        //重新将开关打开
        flag[0] = true;
        //如果对方应答文件中reply或者success显示false 这边可能需要重新发送(递归调用)
        if (!"TRUE".equals(resVo.getReply()) || !method.equals(resVo.getMethod())) {
            //CreateReqFile(reply, flag, param,method);
            log.error("****************" + resVo.getMethod() + "数据上传出错**********");
            log.error("错误信息如下:" + resVo.getMessage());
        }
        f.delete();
        log.info("===========退出循环============");
    }


    /**
     * 9上传医保专用
     * @param reply
     * @param flag
     * @param param
     * @param method
     * @throws IOException
     * @throws BaseBusinessException
     * @return
     */
    public static ScxsResVo createReqFileFor9(File reply, boolean[] flag, Object param, String method) throws IOException,BaseBusinessException {
        log.info("------------------进入CreateReqFile-----------------------");
        //拼装请求入参
        ReqVo reqVo = new ReqVo();
        reqVo.setMethod(method);
        reqVo.setRequest("TRUE");
        reqVo.setParam(param);
        //请求出参结果
        String result = "";
        //请求出参对象
        ScxsResVo scxsResVo = new ScxsResVo();
        //删除以前的响应文件
        if (reply.exists()){
            reply.delete();
        }
        //生成请求文件request.txt
        writeJsonToTxt(reqVo);
        //使程序阻塞,等待文件变动,当产生应答文件后,跳出死循环(此时存在一种情况就是应答文件正在创建,但是还没有创建完成,文件被占用因此才会有两个此死循环判断)
        if (flag[0]) {
            log.info("程序阻塞,等待创建响应文件");
        }
        //这里要在循环外面加一个日期,循环里面创建一个日期进行比较,如果超时,则退出程序并且抛出异常
        LocalDateTime start = LocalDateTime.now();
        while (flag[0]) {
            LocalDateTime end = LocalDateTime.now();
            long between = ChronoUnit.MINUTES.between(start, end);
            if (between >= TIME_OUT_MINITE) {
                log.error("请求超时,医保程序并未响应,生成记录文件,并将request文件删除,下次定时任务时候将此时间段信息查出");
                throw new BaseBusinessException(500, "请求超时,医保程序并未响应,生成记录文件,并将request文件删除,下次定时任务时候将此时间段信息查出");
            }
        }
        File f = new File(REPLY_PATH);
        File f1 = new File(REPLY_PATH_TEST);
        //使用renameto来判断文件是否完成(是否被其他程序占用),如果未完成,则不可以拷贝,否则创建过程中我们操作会报错
        log.info("++++++等待reply文件完全创建完成+++++++");
        while (true) {
            f.renameTo(f1);
            if (f.exists()) {

                //如果文件被占用,继续死循环
                continue;
            } else {
                f1.renameTo(f);
            }
            log.info("++++++reply创建文件正式完成+++++++");
            //生成响应文件后重新读取相应内容

            StringBuffer sbf = new StringBuffer();
            try(BufferedReader reader=new BufferedReader(new FileReader(f));){
                String tempStr;
                while ((tempStr = reader.readLine()) != null) {
                    sbf.append(tempStr);
                }
                reader.close();
                result = sbf.toString();
                scxsResVo = JSONUtil.parseObj(result).toBean(ScxsResVo.class);
            }catch (Exception e){
                log.error(e.toString());
            }
            break;
        }
        log.info("程序阻塞退出,已经创建响应文件");
        //假设对方程序应答文件产生
        //重新将开关打开
        flag[0] = true;
        //如果对方应答文件中reply或者success显示false 这边可能需要重新发送(递归调用)
        if (!"TRUE".equals(scxsResVo.getReply()) || !method.equals(scxsResVo.getMethod())) {
            //CreateReqFile(reply, flag, param,method);
            log.error("*******响应文件包含错误信息*********" + scxsResVo.getMethod() + "数据上传出错**********");
            log.error("错误信息如下:" + scxsResVo.getMessage());
        }
        f.delete();
        log.info("===========退出循环============");
        return scxsResVo;
    }


    /**
     * 生成request.txt文件
     *
     * @param reqVo
     * @throws IOException
     */
    public static void writeJsonToTxt(ReqVo reqVo) throws IOException {
        log.info("开始生成request.txt文件");
        //写文件
        File f = new File(REQUEST_PATH);

        try( OutputStreamWriter write = new OutputStreamWriter(new FileOutputStream(f), "UTF-8");
             BufferedWriter writer = new BufferedWriter(write);) {
            //如果存在,则将之前的删除
            if (f.exists()) {
                f.delete();
            }
            //如果没有删除成功,先用之前的,内容会被覆盖掉(如果文件被占用那就没办法了,再见)
            if (!f.exists()) {
                f.createNewFile();
            }
            JSON jsonObject = JSONUtil.parse(reqVo);
            String s = JSONUtil.toJsonStr(jsonObject);
            writer.write(s);
            writer.close();
            write.close();
        } catch (IOException e) {
            log.error("************生成request.文件失败******************");
            log.error("************生成request.文件失败,method:" + reqVo.getMethod());
            throw e;
        }
        log.info("生成request.txt文件结束");
    }

    /**
     * 将第几次错误记录到日志文件中
     *
     * @param taskError
     * @throws IOException
     */
    public static void taskErrorRecord(int taskError) {
        File file = new File("D:/易联众药企通/yddjjk/taskError.properties");
        if (!file.exists()) {
            cn.hutool.core.io.FileUtil.touch(file);
        }

        Properties pro = new Properties();

        //读取属性文件a.properties


        try(InputStream in = new BufferedInputStream(new FileInputStream("D:/易联众药企通/yddjjk/taskError.properties"));
            PrintStream printStream = new PrintStream(file);) {

            pro.load(in);     ///加载属性列表

            pro.setProperty("taskError",
                    (pro.getProperty("taskError") == null ? "" : pro.getProperty("taskError")) + "," + taskError);
            pro.store(printStream, "utf-8");
            pro.load(in);
            printStream.close();
            in.close();
        } catch (IOException e) {
            log.error("创建错误定时任务记录文件失败");
        }

        // List<String> a1 = Arrays.asList(((String) pro.get("taskError")).substring(taskError).split(","));
    }


    public static List<String> getTaskError() {
        File file = new File("D:/易联众药企通/yddjjk/taskError.properties");
        if (file.exists()) {
            Properties pro = new Properties();
            //读取属性文件a.properties

            try (InputStream in = new BufferedInputStream(new FileInputStream("D:/易联众药企通/yddjjk/taskError.properties"));){
                pro.load(in);
                in.close();
            } catch (IOException e) {
                log.error("创建错误定时任务记录文件失败");
            }
            List<String> list = Arrays.asList(((String) pro.get("taskError")).substring(1).split(","));
            return list;

        }
        return null;
    }

    public static void main(String[] args) {
       /* FileReader fileReader = new FileReader("D:/易联众药企通/yddjjk/20200509_YPLSXX_085222_reply.txt");
        String result = fileReader.readString();
        ScxsResVo scxsResVo = JSONUtil.parseObj(result).toBean(ScxsResVo.class);
        scxsResVo.setEntity(JSONUtil.toBean((JSONObject) scxsResVo.getEntity(),Demo.class));

        System.out.println(((Demo)scxsResVo.getEntity()).getName());*/
    }

}
